package su.levenetc.ohos.draggableview;

import ohos.agp.components.*;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Texture;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.media.image.PixelMap;
import ohos.media.image.PixelMap.InitializationOptions;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.TouchEvent;
import su.levenetc.ohos.draggableview.utils.Utils;

/**
 * Created by Eugene Levenetc.
 */
public class DragController<T extends ComponentContainer & DragController.IDragViewGroup> {
    private Component selectedView;
    private Point downEventPoint = new Point();
    private DraggableView draggableView;
    private VelocityDetector velocityTracker = VelocityDetector.obtainInstance();
    private T viewGroup;

    public DragController(T viewGroup) {
        this.viewGroup = viewGroup;
    }

    public boolean onTouchEvent(TouchEvent event, Component component) {
        final int action = event.getAction();
        final float x = Utils.getTouchX(event, component);
        final float y = Utils.getTouchY(event, component);
        final boolean isInDragSession = draggableView != null;

        if (action == TouchEvent.PRIMARY_POINT_DOWN && !isInDragSession) {
            selectedView = viewGroup.onDownEvent((int) x, (int) y);

            if (selectedView != null) {
                downEventPoint.modify(x, y);
                addDraggable();
                return true;
            }

        } else if (isInDragSession && action == TouchEvent.PRIMARY_POINT_UP || action == TouchEvent.CANCEL) {
            velocityTracker.clear();
            viewGroup.onDragEnd();
            return true;
        } else if (isInDragSession && action == TouchEvent.POINT_MOVE) {
            draggableView.onMoveAction(event, component);
            return true;
        }

        return false;
    }

    private void addDraggable() {
        viewGroup.onDragStart();

        PixelMap bitmap;
        float selectedViewX = selectedView.getContentPositionX();
        float selectedViewY = selectedView.getContentPositionY();
        downEventPoint.modify(downEventPoint.getPointX() - selectedViewX, downEventPoint.getPointY() - selectedViewY);

        if (selectedView instanceof Image) {
            Image image = (Image) selectedView;
            bitmap = image.getPixelMap();
            Rect rect = new Rect(0, 0, bitmap.getImageInfo().size.width, bitmap.getImageInfo().size.height);
            PixelMap.InitializationOptions options = new InitializationOptions();
            options.size = new Size(image.getWidth(), image.getHeight());
            bitmap = PixelMap.create(bitmap, rect, options);
        } else {
            // 非Image暂时无法转成PixelMap进行动画
            PixelMap.InitializationOptions options = new InitializationOptions();
            options.size = new Size(selectedView.getWidth(), selectedView.getHeight());
            bitmap = PixelMap.create(options);
            Canvas canvas = new Canvas(new Texture(bitmap));
            Paint paint = new Paint();
            paint.setColor(Color.WHITE);
            canvas.drawRect(0, 0, selectedView.getWidth(), selectedView.getHeight(), paint);
            paint.setColor(Color.BLACK);
            paint.setTextSize(30);
            String string = "非Image，暂无图片";
            float textLength = paint.measureText(string);
            canvas.drawText(paint, string, selectedView.getWidth() / 2 - textLength / 2, selectedView.getHeight() / 2 + paint.getTextSize() * 3 / 4);
        }
        draggableView = viewGroup.createDraggableView(
                bitmap,
                velocityTracker,
                new Point(selectedViewX, selectedViewY),
                downEventPoint
        );
        viewGroup.getContainerForDraggableView().addComponent(draggableView);
    }

    public void finishDrag() {
        viewGroup.getContainerForDraggableView().removeComponent(draggableView);
        draggableView = null;
        selectedView = null;
    }

    public DraggableView getDraggableView() {
        return draggableView;
    }

    public interface IDragViewGroup {
        /**
         * Should be returned view which can be dragged
         * or null if there is no such view
         * @param x position x
         * @param y position y
         *
         * @return the Component
         */
        Component onDownEvent(int x, int y);

        /**
         * get ComponentContainer where draggable view will be added
         * @return ComponentContainer where draggable view will be added
         */
        ComponentContainer getContainerForDraggableView();

        /**
         * Calls after draggable view was created.
         * Some animations could be started.
         * Also selected view should be hided.
         */
        void onDragStart();

        /**
         * Calls after ACTION_UP or ACTION_CANCEL event.
         * E.g. user finished dragging.
         * Last position of draggable could be received with {@link IDragViewGroup#onMoveEvent}
         * <p/>
         * !!!
         * Finally must be called {@link DragController#finishDrag()}
         * !!!
         */
        void onDragEnd();

        void onMoveEvent(float x, float y);

        DraggableView createDraggableView(PixelMap bitmap,
                                          VelocityDetector velocityTracker,
                                          Point selectedViewPoint,
                                          Point downEventPoint
        );
    }
}